package com.irixel.hdc.controllers;

import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.security.Principal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.csvreader.CsvWriter;
import com.irixel.hdc.dto.AyudaEconomicaDTO;
import com.irixel.hdc.dto.DetalleGastosDTO;
import com.irixel.hdc.dto.FacturaDTO;
import com.irixel.hdc.dto.FondoFijoDTO;
import com.irixel.hdc.dto.TipoFacturaDTO;
import com.irixel.hdc.utils.ZipUtils;

@Controller
public class ReporteController {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private TipoFacturaController tipoFacturaController;

	@Autowired
	private FacturaController facturaController;

	@RequestMapping("report")
	public @ResponseBody
	String reporte(Principal principal, HttpServletResponse response)
			throws IOException {
		String ret = "";

		// Let's generate the data for the "fondo fijo" book
		String fondoFijoBook = "";
		List<TipoFacturaDTO> tipos = tipoFacturaController.getTipos();
		List<FacturaDTO> facturas = facturaController.getFacturas(principal);
		Map<String, byte[]> archivos = new HashMap<String, byte[]>();

		for (TipoFacturaDTO tipo : tipos) {
			fondoFijoBook += generarTipoCSV(tipo, facturas);
		}
		fondoFijoBook = fondoFijoBook.replace("\n", "\r\n");
		archivos.put("fondofijo.csv",
				fondoFijoBook.getBytes(Charset.forName("UTF-8")));

		// Ordering facturas
		Collections.sort(facturas, new Comparator<FacturaDTO>() {
			@Override
			public int compare(FacturaDTO o1, FacturaDTO o2) {
				int ret = o1.getTipo().compareToIgnoreCase(o2.getTipo());
				if (ret == 0) {
					ret = o1.getFecha().compareTo(o2.getFecha());
				}
				return ret;
			}
		});

		// Now, "Detalle de gastos" book
		String detalleGastosBook = generarDetalleGastosBook(facturas);
		detalleGastosBook = detalleGastosBook.replace("\n", "\r\n");
		archivos.put("detallegastos.csv",
				detalleGastosBook.getBytes(Charset.forName("UTF-8")));

		// Finally, "Ayuda economica" book
		String ayudaEconomicaBook = generarAyudaEconomicaBook(facturas);
		ayudaEconomicaBook = ayudaEconomicaBook.replace("\n", "\r\n");
		archivos.put("ayudaeconomica.csv",
				ayudaEconomicaBook.getBytes(Charset.forName("UTF-8")));

		// Returning the zip file
		byte[] zip = ZipUtils.createZip(archivos);

		ServletOutputStream sos = response.getOutputStream();
		response.setContentType("application/zip");
		response.setHeader("Content-Disposition",
				"attachment; filename=\"data-" + System.currentTimeMillis()
						+ ".zip\"");

		sos.write(zip);
		sos.flush();

		return ret;
	}

	private String generarAyudaEconomicaBook(List<FacturaDTO> facturas) {
		StringWriter sw = new StringWriter();

		List<AyudaEconomicaDTO> dtos = new LinkedList<AyudaEconomicaDTO>();
		DateFormat fmt = new SimpleDateFormat("d-MMM-yy");
		NumberFormat numFmt = new DecimalFormat("##");

		for (FacturaDTO f : facturas) {
			if (f.getBeneficiario() != null && !f.getBeneficiario().isEmpty()) {
				AyudaEconomicaDTO dto = new AyudaEconomicaDTO();
				dto.setFecha(fmt.format(f.getFecha()));
				dto.setBeneficiario(f.getBeneficiario() + " ("
						+ f.getDescripcion() + ")");
				dto.setMonto(numFmt.format(f.getMonto()));
				dto.setRUT(f.getRut());
				dto.setTelf(f.getTelf());
				dto.setObservaciones(f.getTipo());

				dtos.add(dto);
			}
		}

		try {
			CsvWriter csvOutput = new CsvWriter(sw, '\t');
			dtoToCsv(new String[] { "fecha", "beneficiario", "RUT", "monto",
					"telf", "observaciones", "space", "ceco" }, dtos, csvOutput);
			csvOutput.endRecord();
			csvOutput.endRecord();
			csvOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return sw.toString();
	}

	private String generarDetalleGastosBook(List<FacturaDTO> facturas) {
		StringWriter sw = new StringWriter();

		List<DetalleGastosDTO> dtos = new LinkedList<DetalleGastosDTO>();
		DateFormat fmt = new SimpleDateFormat("d-MMM-yy");
		NumberFormat numFmt = new DecimalFormat("##");
		for (FacturaDTO f : facturas) {
			DetalleGastosDTO dto = new DetalleGastosDTO();
			dto.setCuenta(f.getCuenta());
			dto.setFecha(fmt.format(f.getFecha()));
			dto.setDescripcion(f.getDescripcion());
			dto.setNumDocumento(f.getNumFactura());
			dto.setTipoGasto(f.getTipo());
			dto.setTotal(numFmt.format(f.getMonto()));

			dtos.add(dto);
		}

		try {
			CsvWriter csvOutput = new CsvWriter(sw, '\t');
			dtoToCsv(new String[] { "fecha", "descripcion", "numDocumento",
					"space", "tipoGasto", "space", "cuenta", "space", "space",
					"ceco", "total" }, dtos, csvOutput);
			csvOutput.endRecord();
			csvOutput.endRecord();
			csvOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return sw.toString();
	}

	private String generarTipoCSV(TipoFacturaDTO tipo, List<FacturaDTO> facturas) {
		StringWriter sw = new StringWriter();
		List<FondoFijoDTO> dtos = new LinkedList<FondoFijoDTO>();
		for (TipoFacturaDTO hijo : tipo.getHijos()) {
			int total = 0;
			for (FacturaDTO factura : facturas) {
				if (factura.getIdTipo().longValue() == hijo.getId().longValue()) {
					factura.setTipo(hijo.getNombre());
					factura.setCuenta(hijo.getNumCuenta().toString());
					total += factura.getMonto();
				}
			}

			FondoFijoDTO ffDto = new FondoFijoDTO();
			ffDto.setDescripcion(hijo.getNombre());
			ffDto.setCuenta(hijo.getNumCuenta().toString());
			ffDto.setMonto(total);
			dtos.add(ffDto);
		}

		try {
			CsvWriter csvOutput = new CsvWriter(sw, '\t');
			csvOutput.write(tipo.getNombre());
			csvOutput.endRecord();
			dtoToCsv(new String[] { "descripcion", "space", "cuenta",
					"ordenCo", "centroCosto", "descCeco", "monto" }, dtos,
					csvOutput);
			csvOutput.endRecord();
			csvOutput.endRecord();
			csvOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return sw.toString();
	}

	private void dtoToCsv(String[] fields, List<?> dtos, CsvWriter csvOutput) {
		try {
			for (Object dto : dtos) {
				for (String f : fields) {
					csvOutput.write(BeanUtils.getProperty(dto, f));
				}
				csvOutput.endRecord();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
